<!--文章编写页面,已经实现自动更新功能-->
<template>
  <div>
    <el-row :gutter="24">
      <!--目录区域-->
      <el-col :span="3" v-show="showCatalog">
        <div>
          <div>目录</div>
          <el-button type="text" size="mini" @click="expandAll">全部展开</el-button>
          <el-button type="text" size="mini" @click="unexpandAll">全部关闭</el-button>
          <el-button type="text" size="mini" @click="expandChange">反转</el-button>
          <!--用树形结构展示目录-->
          <el-tree ref="tree" :data="treeData"
                   :indent="10"
                   :props="defaultProps"
                   node-key="id"
                   :highlight-current="true"
                   :expand-on-click-node="false"
                   @node-click="handleNodeClick"></el-tree>
        </div>
      </el-col>
      <!--目录隐藏按钮-->
      <el-col :span="1" style="width: 15px">
        <i v-show="showCatalog" style="cursor: pointer" class="el-icon-s-fold" @click="foldCatalog"></i>
        <i v-show="!showCatalog" style="cursor: pointer" class="el-icon-s-unfold" @click="unfoldCatalog"></i>
        <span style="font-size: 12px">目录</span>
        <el-button v-if="false" type="text" size="mini" @click="showPre=!showPre" style="color: #42b983">
          显<br/>
          示<br/>
          文<br/>
          章<br/>
          预<br/>
          览<br/>
        </el-button>
      </el-col>
      <!--文本区域-->
      <el-col :span="textAreaSpan">
        <div>
          <el-row>
            <!--搜索框-->
            <el-col :xs="24"
                    :sm="12"
                    :md="8"
                    :lg="6">
              <el-input size="mini" style="width:300px" type="text" v-model="searchQuery" placeholder="文章内搜索..."></el-input>
              <el-button type="text" size="mini" @click="searchInEditor">搜索</el-button>
            </el-col>
            <!--文章大标题-->
            <el-col :xs="24"
                    :sm="12"
                    :md="8"
                    :lg="6">
              <el-form ref="savaForm" :model="savaForm" :rules="savaFormRules">
                <el-form-item label="文章标题:" label-width="100px" prop="title">
                  <el-input style="width:100%" type="text" v-model="savaForm.title"
                            clearable show-word-limit :maxlength="255"
                            placeholder="输入文章标题...">
                  </el-input>
                </el-form-item>
              </el-form>
            </el-col>
          </el-row>
          <!--quill编辑框-->
          <div ref="quillEditorContainer" style="height: 600px;"></div>
          <!--下方基础信息-->
          <div>
            <el-row :gutter="24">
              <el-col :xs="24"
                      :sm="12"
                      :md="8"
                      :lg="6">
                <!--当前作者-->
                当前作者:
                <span style="color: crimson">
        {{savaForm.username}}
      </span>
                <!--权限-->
                文章权限:
                <el-select v-model="savaForm.permissionList" style="width: 120px" placeholder="向谁展示">
                  <el-option
                      v-for="item in authorityTypeOptions"
                      :key="item.value"
                      :label="item.label"
                      :value="item.value">
                  </el-option>
                </el-select>
              </el-col>
              <el-col :xs="24"
                      :sm="12"
                      :md="8"
                      :lg="6">
                <!--标签-->
                文章标签:
                <el-tag
                    :key="tag" size="mini"
                    v-for="tag in dynamicTags"
                    closable
                    @close="handleTagClose(tag)">
                  {{tag}}
                </el-tag>
                <el-input
                    class="input-new-tag" style="width: 80px"
                    v-if="inputVisible"
                    v-model="inputValue"
                    ref="saveTagInput"
                    size="small"
                    @keyup.enter.native="handleInputTagConfirm"
                    @blur="handleInputTagConfirm"
                >
                </el-input>
                <el-button v-else class="button-new-tag" size="mini" @click="showAddTagInput">+标签</el-button>
              </el-col>
              <el-col :xs="24"
                      :sm="12"
                      :md="8"
                      :lg="6">
                文章备注:
                <el-input style="width: 80%" placeholder="默认无" v-model="savaForm.remark" :maxlength="50" show-word-limit></el-input>
              </el-col>
              <el-col :xs="24"
                      :sm="12"
                      :md="8"
                      :lg="6">
                <!--手动保存-->
                <el-button type="success" @click="editContent('hand')">手动保存内容</el-button>
                <el-tag  type="success">{{saveTips}}{{selfSaveTextFlag}}</el-tag>
              </el-col>
            </el-row>
          </div>
        </div>
      </el-col>
    </el-row>
    <!--实时渲染  类名缺一不可-->
    <div v-show="showPre" class="ql-container ql-snow" >
      <h2>预览内容</h2>
      <div class="ql-editor" v-html="previewContent" style="height: 100px"></div>
    </div>
  </div>
</template>

<script>
import Quill from 'quill';
import QuillBetterTable from 'quill-better-table'
import ImageResize  from 'quill-image-resize-module';


Quill.register({
  'modules/better-table': QuillBetterTable
}, true)
Quill.register({
  'modules/imageResize': ImageResize
});

import {saveQuillText,editQuillText} from "@/api/quillTextApi";
import {getUserName} from "@/api/token";
export default {
  data() {
    return {
      /**
       * 是否自动保存提示
       */
      /**
       * 是否显示预览
       */
      showPre:false,
      textAreaSpan:23,
      showCatalog:false,
      //tree
      isExpandedAll: true,
      treeData: [
      ],
      defaultProps: {
        children: 'children',
        label: 'label'
      },
      // tree end

      //自动保存提示
      selfSaveTextFlag:'',
      // 当前文章id
      articleId:'',
      dynamicTags: [],
      inputVisible: false,
      inputValue: '',
      authorityTypeOptions:[
        {
          value: '00',
          label: '全部'
        },
        {
          value: '01',
          label: '粉丝'
        },
        {
          value: '02',
          label: '自己'
        }
      ],
      savaForm:{
        articleId:'',
        username: '',
        title:'默认标题',
        content:'',
        createTime: null,
        updateTime: null,
        likes: 0,
        collections: 0,
        tags: '',
        permissionList: '00',
        remark: '无',
      },
      savaFormRules: {
        title: [
          {
            required: true,
            message: '请输入文章标题',
            trigger: 'blur'
          },
          {
            min: 1,
            max: 255,
            message: '长度在 1 到 255 个字符',
            trigger: 'blur'
          }
        ]
      },
      quill: null,
      quillShow: null,
      /**
       * 文章内容
       */
      content: '',
      /**
       * 搜索内容
       */
      searchQuery:'',
      /**
       * 目录html定位
       */
      searchCatalogQuery:'',
      previewContent: '',
      saveAutoTimer:null,
      saveTips:''
    };
  },
  mounted() {
    this.getUserName()
    // quill初始化
    const quillEditorContainer = this.$refs.quillEditorContainer;
    this.quill = new Quill(quillEditorContainer, {
      theme: 'snow',
      modules: {
        table:false, // 禁用表格
        'better-table': {
          operationMenu: {
            items: {
              unmergeCells: {
                text: '拆分单元格'
              }
            },
            color: {
              colors: ['#fff', 'red', 'rgb(0, 0, 0)','blue','green','yellow'],  // colors in operationMenu
              text: 'Background Colors'  // subtitle
            }
          }
        },
        keyboard: {
          bindings: QuillBetterTable.keyboardBindings
        },
        imageResize: {
          // modules 所有图片模块
          modules: [ 'Resize', 'DisplaySize', 'Toolbar' ],
          // // 样式配置
          // handleStyles: {
          //   backgroundColor: 'black',
          //   border: 'none',
          //   color: 'white'
          //   // other camelCase styles for size display
          // },
          // displayStyles: {
          //   backgroundColor: 'black',
          //   border: 'none',
          //   color: white
          //   // other camelCase styles for size display
          // },
          // // ...
          // toolbarStyles: {
          //   backgroundColor: 'black',
          //   border: 'none',
          //   color: white
          //   // other camelCase styles for size display
          // },
          // toolbarButtonStyles: {
          //   // ...
          // },
          // toolbarButtonSvgStyles: {
          //   // ...
          // },
        },
        toolbar: [
          // 字体样式
          ['bold', 'italic', 'underline', 'strike'],
          // 标题快捷键
          [{ header: 1 }, { header: 2 },{ header: 3 },{ header: 4 },{ header:5 },{ header: 6}], // 添加 h1 和 h2 选项
          // 标题级别
          [{header: [1, 2, 3, 4, 5, 6,false]}],
          // 字体选择
          [{font: []}],
          // 字体大小
          [{size: ['small', false, 'large', 'huge']}],
          // 文字颜色和背景颜色
          [{color: []}, {background: []}],
          // 引用和代码块
          ['blockquote', 'code-block'],
          // 有序列表和无序列表
          [{list: 'ordered'}, {list: 'bullet'}],
          // 缩进和凸出
          [{indent: '-1'}, {indent: '+1'}],
          // 插入链接、图片和视频
          ['link', 'image', 'video'],
          // 插入表格
          ['table'],
          // 清除格式
          ['clean'],
          // 文本对齐方式
          [{align: ['', 'center', 'right', 'justify']}],
          // 文本方向
          [{'direction': 'rtl'}],
          // 幂等
          [{'script': 'sub'}, {'script': 'super'}],      // superscript/subscript
        ],
      }
    });

    // header的点击事件   就是默认事件  可加可不加
    this.quill.getModule('toolbar').addHandler('header', (value) =>{
      // 正常设置
      this.quill.format('header', value);  // value是整型
    });

    //表格点击事件
    this.quill.getModule('toolbar').addHandler('table', () =>{
      // 采用better-table插件
      let tableModule = this.quill.getModule('better-table')
      tableModule.insertTable(3, 3)
    });

    // 先判断是否从读取文章页面跳入
    let articleAllInfo = this.$route.query['articleAllInfo'];
    // 编辑文章
    if (articleAllInfo != null) {
      this.articleId = articleAllInfo.articleId;
      this.savaForm.articleId = articleAllInfo.articleId;
      this.savaForm.title = articleAllInfo['title'];
      this.savaForm.username = articleAllInfo.username;
      this.savaForm.content = articleAllInfo.content;
      // this.savaForm.createTime = articleAllInfo.createTime;
      // this.savaForm.updateTime = articleAllInfo.updateTime;
      this.savaForm.collections = articleAllInfo.collections;
      this.savaForm.likes = articleAllInfo.likes;
      if(articleAllInfo.tags.includes(',')){
        this.dynamicTags = articleAllInfo.tags.split(',')
        this.savaForm.tags = articleAllInfo.tags
      }
      else {
        if(articleAllInfo['tags']===''){
          this.dynamicTags = []
          this.savaForm.tags = ''
        }
        else {
          this.dynamicTags.push(articleAllInfo.tags)
          this.savaForm.tags = articleAllInfo.tags
        }
      }
      this.savaForm.permissionList = articleAllInfo.permissionList;
      this.savaForm.remark = articleAllInfo.remark;
      this.quill.root.innerHTML = articleAllInfo['content']
      this.treeData = this.getCatalogFromStr(articleAllInfo['content'])
      this.treeData = this.convertToTree(this.treeData)
      this.autoSave()
      this.quill.on('text-change', this.generateTableOfContents);
    }
    // 新增文章
    else {
      this.quill.on('text-change', this.generateTableOfContents);
      // 开启自动保存
      this.saveContent()
    }
    this.quill.on('text-change', () => {
      this.content = this.quill.root.innerHTML;
      this.previewContent = this.quill.root.innerHTML;
      // this.autoSave()
    });
  },
  methods: {
    getUserName(){
      this.savaForm.username =  getUserName()
    },
    /**
     * 从字符串中获取目录
     * @param str
     * @returns {*[]}
     */
    getCatalogFromStr(str) {
      let reg = /<h[1-6]>(.*?)<\/h[1-6]>/g
      let arr = str.match(reg)
      if (arr === null)
        return null
      // 转arr转扁平树形结构
      let tree = []
      arr.forEach(item => {
        let reg = /<h([1-6])>(.*?)<\/h[1-6]>/
        let res = reg.exec(item)
        let obj = {
          text: res[2],
          level: parseInt(res[1]),
          // children: []
        }
        tree.push(obj)
      })
      return tree
    },
    /**
     * 隐藏目录
     */
    foldCatalog(){
      this.showCatalog = !this.showCatalog
      this.textAreaSpan = 23
    },
    /**
     * 显示目录
     */
    unfoldCatalog(){
      this.showCatalog = !this.showCatalog
      this.$nextTick(()=>{
        this.textAreaSpan = 20
      })
      this.$forceUpdate()
    },
    /**
     * 自动保存
     */
    autoSave() {
      this.saveTips = '自动保存保护中:'
      this.editContent()
      // 取消定时保存的形式  改为监听到文章内容变化 就保存    在quill的text-change内   或者watch整个表单
      // this.saveAutoTimer = setInterval(() => {
      //   this.editContent()
      // }, 30000); // 每 1000 毫秒（1 秒）更新一次时间
    },
    /**
     * 新增保存  此保存为 html
     */
    saveContent() {
      this.$refs.savaForm.validate((valid) => {
        if (valid) {
          // 开始时立马保存
          this.savaForm.content=this.content
          saveQuillText(this.savaForm).then((res)=>{
            // 保存成功后开启自动保存
            this.autoSave()
            this.$message.success('已开启自动保存!')
            this.articleId = res.data.articleId
          }).catch((err)=>{

          })
        }
      })
    },

    /**
     * 修改保存  此保存为 html
     */
    editContent(val){
      this.savaForm.content=this.content
      this.savaForm.articleId = this.articleId   // 根据新增时返回来的id进行修改
      editQuillText(this.savaForm).then((res)=>{
        if(val==='hand')
            this.$message.success('手动保存成功!')
        let currentTime = this.formattedTime()
        this.selfSaveTextFlag = '已保存'+currentTime
      }).catch((err)=>{

      })
    },
    /**
     * currentTime格式化
     * @returns {string}
     */
    formattedTime() {
      let date = new Date();
      let hours = date.getHours();
      if(hours.toString().length===1){
        hours = '0'+hours
      }
      let minutes = date.getMinutes();
      if(minutes.toString().length===1){
        minutes = '0'+minutes
      }
      let seconds = date.getSeconds();
      if(seconds.toString().length===1){
        seconds = '0'+seconds
      }
      return `${hours}:${minutes}:${seconds}`;
    },
    /**
     * 标签移除操作
     * @param tag
     */
    handleTagClose(tag) {
      this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1);
      // console.log(this.dynamicTags)
      if(this.dynamicTags.length===0){
        this.savaForm.tags=''
      }else {
        this.savaForm.tags=this.dynamicTags.join(',')
      }
    },

    /**
     * 显示标签输入框
     */
    showAddTagInput() {
      this.inputVisible = true;
      this.$nextTick(_ => {
        this.$refs.saveTagInput.$refs.input.focus();
      });
    },

    /**
     * 确认键入的标签
     */
    handleInputTagConfirm() {
      let inputValue = this.inputValue;
      if (inputValue) {
        this.dynamicTags.push(inputValue);
      }
      this.inputVisible = false;
      this.inputValue = '';
      this.savaForm.tags=this.dynamicTags.join(',')
      // console.log(this.savaForm.textTag)
    },

    /**
     * 将目录数组转换为树形结构
     * @param data
     * @returns {*[]}
     */
    convertToTree(data) {
      const tree = [];
      let currentParent = null;
      if (data === null)
        return null
      data.forEach((item ,index)=> {
        if (item.level === 1) {
          // 遇到 level 为 1 的，创建新的树节点并作为父节点
          currentParent = {
            label: item.text,
            value: item.text,
            id: index,
            children: []
          };
          tree.push(currentParent);
        }
        else {
          let parent = currentParent;
          while (parent && parent.level < item.level) {
            if (!parent.children) {
              parent.children = [];
            }
            parent = parent.children[parent.children.length - 1];
          }
          // 如果当前节点的父节点parent就不存在  说明没有点击h1 则直接创建一个h1的节点 然后返回
          if (!parent) {
            this.quill.format('header', 1);
            return
            // parent = {
            //   label: '默认一级标题',
            //   value: 'h1',
            //   id: index,
            //   children: []
            // };
            // tree.push(parent);
          }
          // 如果当前节点的父节点parent不存在children属性，则创建一个空数组
          if (!parent.children) {
            parent.children = [];
          }
          // 根据 level 创建对应的节点层级
          const newNode = {
            label: item.text,
            value: item.text,
            id: index,
            children: []
          };
          if (item.level === 2) {
            parent.children.push(newNode);
          }
          else if (item.level === 3) {
            let secondLevelParent = parent.children[parent.children.length - 1];
            if (!secondLevelParent) {
              return;
            }
            if (!secondLevelParent.children) {
              secondLevelParent.children = [];
            }
            secondLevelParent.children.push(newNode);
          }
          else if (item.level === 4) {
            const secondLevelParent = parent.children[parent.children.length - 1];
            if (!secondLevelParent) {
              return;
            }
            let thirdLevelParent = secondLevelParent.children[secondLevelParent.children.length - 1];
            if (!thirdLevelParent) {
              return;
            }
            if (!thirdLevelParent.children) {
              thirdLevelParent.children = [];
            }
            thirdLevelParent.children.push(newNode);
          }
          else if (item.level === 5) {
            const secondLevelParent = parent.children[parent.children.length - 1];
            if (!secondLevelParent) {
              return;
            }
            let thirdLevelParent = secondLevelParent.children[secondLevelParent.children.length - 1];
            if (!thirdLevelParent) {
              return;
            }
            let fourthLevelParent = thirdLevelParent.children[thirdLevelParent.children.length - 1];
            if (!fourthLevelParent) {
              return;
              // fourthLevelParent = {
              //   label: '默认四级标题',
              //   value: 'h4',
              //   id: index,
              //   children: []
              // };
              // secondLevelParent.children.push(fourthLevelParent);
            }
            if (!fourthLevelParent.children) {
              fourthLevelParent.children = [];
            }
            fourthLevelParent.children.push(newNode);
          }
          else if (item.level === 6) {
            const secondLevelParent = parent.children[parent.children.length - 1];
            if (!secondLevelParent) {
              return;
            }
            let thirdLevelParent = secondLevelParent.children[secondLevelParent.children.length - 1];
            if (!thirdLevelParent) {
              return;
            }
            let fourthLevelParent = thirdLevelParent.children[thirdLevelParent.children.length - 1];
            if (!fourthLevelParent) {
              return;
            }
            let fifthLevelParent = fourthLevelParent.children[fourthLevelParent.children.length - 1];
            if (!fifthLevelParent) {
              return;
              // fifthLevelParent = {
              //   label: '默认五级标题',
              //   value: 'h5',
              //   id: index,
              //   children: []
              // };
              // secondLevelParent.children.push(fifthLevelParent);
            }
            if (!fifthLevelParent.children) {
              fifthLevelParent.children = [];
            }
            fifthLevelParent.children.push(newNode);
          }
        }
      });

      return tree;
    },
    /**
     * 确保数组的第一个元素是level为1的  当直接点击h2的时候不会报错
     * @param arr
     * @returns {*}
     */
    ensureStartsWithLevel1(arr) {
      if (arr.length > 0 && arr[0].level!== 1) {
        arr.unshift({
          level: 1,
          text: '一级目录'
        });
      }
      return arr;
    },
    /**
     * 处理quill的h1-h6数组  获取h1-h6的html内容
     * @param arr
     * @returns {*[]}
     */
    processArray(arr) {
      let result = [];
      for (let i = 0; i < arr.length; i++) {
        if (arr[i].hasOwnProperty('attributes')) {
          if (i > 0 && arr[i - 1].hasOwnProperty('insert')) {
            arr[i].insert = arr[i - 1].insert + arr[i].insert;
          }
          result.push(arr[i]);
        }
      }
      return result;
    },
    /**
     * 编辑时 自动生成目录
     */
    generateTableOfContents() {
      if (this.quill) {
        const contents = this.quill.getContents();
        // const tableOfContents = [];
        let treeCatalog = [];
        // console.log(contents.ops)
        let arr = this.processArray(contents.ops)
        // 根据h123456来进行目录判断
        arr.forEach((item) => {
          if (item && item.attributes['header'] && item.insert) {
            // tableOfContents.push({
            //   level: item.attributes['header'],
            //   text: item.insert.replace('\n','')
            // });
            treeCatalog.push({
              level: item.attributes['header'],
              text: item.insert.split('\n')[item.insert.split('\n').length-2]
            });
          }
        });
        // this.tableOfContents = tableOfContents;
        // console.log(treeCatalog)
        // treeCatalog = this.ensureStartsWithLevel1(treeCatalog)
        this.treeData = this.convertToTree(treeCatalog);
        // 生成后自动展开
        // console.log(this.treeData,' 99999')
        this.$nextTick(() =>{
          this.expandAll()
        })
      }
    },

    /**
     * 目录展开状态切换
     */
    expandChange() {
      const tree = this.$refs.tree
      // console.log(tree.store['nodesMap'])
      let nodes = tree.store['nodesMap']
      Object.keys(nodes).forEach(key => {
        nodes[key].expanded = !nodes[key].expanded
      })
    },
    /**
     * 展开所有目录
     */
    expandAll() {
      const tree = this.$refs.tree
      // console.log(tree.store['nodesMap'])
      let nodes = tree.store['nodesMap']
      Object.keys(nodes).forEach(key => {
        nodes[key].expanded = tree
      })
    },
    /**
     * 关闭所有目录
     */
    unexpandAll() {
      const tree = this.$refs.tree
      // console.log(tree.store['nodesMap'])
      let nodes = tree.store['nodesMap']
      Object.keys(nodes).forEach(key => {
        nodes[key].expanded = false
      })
    },

    /**
     * 点击目录
     * @param data
     * @param node
     */
    handleNodeClick(data,node) {
      let level = 1;
      let parent = node.parent;
      while (parent) {
        level++;
        parent = parent.parent;
      }
      level--
      // console.log(`点击的节点是第${level}级节点，节点信息：`, data);

      let clickText = data.label
      // console.log('标签',clickText)
      // 为了精确定位目录   加上类似h1这样的标签  防止定位到普通文本
      clickText = `<h${level}>${clickText}</h${level}>`

      this.searchCatalogQuery = clickText
      this.searchCatalogInEditor()
    },

    /**
     * 处理所有文本  将数据库的html文本的h标签中多余的标签处理掉  以更好的去目录进行匹配
     * @param str
     */
    processAllText(str) {
      let parser = new DOMParser();
      let doc = parser.parseFromString(str, 'text/html');

      let hElements = doc.getElementsByTagName('h1');
      for (let i = 0; i < hElements.length; i++) {
        let hElement = hElements[i];
        let text = hElement.textContent;
        hElement.innerHTML = text;
      }

      hElements = doc.getElementsByTagName('h2');
      for (let i = 0; i < hElements.length; i++) {
        let hElement = hElements[i];
        let text = hElement.textContent;
        hElement.innerHTML = text;
      }
      hElements = doc.getElementsByTagName('h3');
      for (let i = 0; i < hElements.length; i++) {
        let hElement = hElements[i];
        let text = hElement.textContent;
        hElement.innerHTML = text;
      }
      hElements = doc.getElementsByTagName('h4');
      for (let i = 0; i < hElements.length; i++) {
        let hElement = hElements[i];
        let text = hElement.textContent;
        hElement.innerHTML = text;
      }
      hElements = doc.getElementsByTagName('h5');
      for (let i = 0; i < hElements.length; i++) {
        let hElement = hElements[i];
        let text = hElement.textContent;
        hElement.innerHTML = text;
      }
      hElements = doc.getElementsByTagName('h6');
      for (let i = 0; i < hElements.length; i++) {
        let hElement = hElements[i];
        let text = hElement.textContent;
        hElement.innerHTML = text;
      }
      // 获取doc.documentElement的body
      let body = doc.body;
      let result = body.innerHTML;
      // 去掉换行符与空格
      // result = result.replace(/\s/g, '');
      result = result.replace(/\n/g, '');
      // console.log('处理后的全文本',result);
      return result
    },
    /**
     * 点击目录  在文中定位
     * @returns {null}
     */
    searchCatalogInEditor() {
      let searchText = this.searchCatalogQuery
      let allText = this.quill.root.innerHTML
      allText = this.processAllText(allText)
      if(!searchText) return null
      // console.log('搜索目录',searchText)
      // console.log('全文本',allText)
      let index = allText.indexOf(searchText)
      // console.log(index)
      if (index === -1) return null
      let before = allText.substring(0, index);
      let match = allText.substring(index, index + searchText.length);
      let after = allText.substring(index + searchText.length);
      // 全部文本重新渲染   达到定位效果
      this.matchText = '<span class="clickEle" style="background-color: rgba(206,206,36,0)">' + match + '</span>'
      // 事先复制一份数据  用于恢复
      let contentCopy = JSON.parse(JSON.stringify(this.quill.root.innerHTML))
      this.quill.root.innerHTML = before + this.matchText + after;

      // 卧槽  这样就简单多了
      this.$nextTick(()=>{
        document.querySelector('.clickEle').scrollIntoView({})
        // 定位完之后  将文本恢复至数据库状态
        this.quill.root.innerHTML= contentCopy
      })
      // // 滚动效果已经实现   改变top即可
      // let quillEditorContainer = document.querySelector('.ql-editor ')
      // let topNum = 200  // 微调
      // this.$nextTick(() => {
      //   quillEditorContainer.scrollTo({
      //     top: topNum,
      //     behavior: 'smooth'
      //   });
      // })
    },


    /**
     * 搜索并滚动到指定文本
     */
    searchInEditor() {
      // 这个index从0开始，换行算一个
      const index = this.findTextIndex(this.quill, this.searchQuery);
      if (index === -1) {
        this.$message.warning('Text not found.');
        return;
      }
      const textLength = this.searchQuery.length;
      const bounds = this.getTextBounds(this.quill, index,textLength);
      this.textDistanceFromTop = this.calculateDistanceToTop(this.quill, bounds);

      // 滚动效果已经实现   改变top即可
      let quillEditorContainer = document.querySelector('.ql-editor ')
      let topNum = this.textDistanceFromTop+146    // 微调
      this.$nextTick(() => {
        quillEditorContainer.scrollTo({
          top: topNum,
          behavior: 'smooth'
        });
      })

    },
    findTextIndex(quill, text) {
      const delta = quill.getContents();
      let index = 0;
      let found = false;

      delta.ops.forEach(op => {
        if (typeof op.insert === 'string') {
          const match = op.insert.indexOf(text);
          if (match !== -1) {
            found = true;
            index += match;
          } else {
            index += op.insert.length;
          }
        } else {
          index += op.insert.length;
        }
      });

      return found ? index : -1;
    },
    getTextBounds(quill, startIndex, length) {
      const range = { index: startIndex, length };
      return quill.getBounds(range);
    },
    calculateDistanceToTop(quill, bounds) {
      const container = quill.root; // 获取 Quill 编辑器的容器
      return bounds.top - container.getBoundingClientRect().top;
    },
  },
  beforeDestroy() {
    clearInterval(this.saveAutoTimer)
  },
  watch: {
    // 监听savaForm 表单
    'content'(newVal, oldVal) {
      this.autoSave()
    },
    'savaForm.permissionList'(newVal, oldVal) {
      this.autoSave()
    },
    'savaForm.tags'(newVal, oldVal) {
      this.autoSave()
    }
    ,
    'savaForm.remark'(newVal, oldVal) {
      this.autoSave()
    }
  }
};
</script>

<style>
/* 可以根据需要添加一些样式 */
.ql-toolbar {
  border: 1px solid #ccc;
}

.ql-container {
  border: 1px solid #ccc;
}

.el-tag + .el-tag {
  margin-left: 10px;
}
.button-new-tag {
  margin-left: 10px;
  height: 32px;
  line-height: 30px;
  padding-top: 0;
  padding-bottom: 0;
}
.input-new-tag {
  width: 90px;
  margin-left: 10px;
  vertical-align: bottom;
}
</style>